package com.tjbank.cssys.service.config.shiro.stateless.filter;

import com.alibaba.fastjson.JSON;
import com.tjbank.cssys.framework.base.api.Response;
import com.tjbank.cssys.framework.base.api.ResultCodeEnum;
import com.tjbank.cssys.framework.base.enums.ExceptionCodeEnum;
import com.tjbank.cssys.service.config.shiro.stateless.token.StatelessToken;
import com.tjbank.cssys.service.util.IYCPEncryptor;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.AccessControlFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StringUtils;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;


/**
 * Copyright © 天阳宏业科技股份有限公司 - All Rights Reserved
 *
 * @description: 无状态即通过Token方式访问的权限过滤器.
 * @author: <a href="mailto:guzheng01@tansun.com.cn>Joey Gu</a>
 * @date: 2020-06-08 17:22
 **/
public class StatelessAuthcFilter extends AccessControlFilter {

    private static final Logger log = LoggerFactory.getLogger(StatelessAuthcFilter.class);
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        Subject subject = getSubject(request, response);
        return subject.isAuthenticated();
    }

    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        // 登录状态判断
        Subject subject = getSubject(request, response);
        if (subject.isAuthenticated()) {
            return true;
        }
        // 1、客户端产生的Token(可能是由服务器先返回的Token也可能是客户端通过共有Key产生的)
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        String token = httpRequest.getHeader("Access-Token");
        try {
            // 2、对token解密,获取登陆码
            String decrypt = IYCPEncryptor.decrypt(token);
            String loginCode = decrypt.substring(0, decrypt.indexOf("_"));
            boolean flag= redisTemplate.opsForHash().hasKey(loginCode,token);
            if(!flag){
                onLoginFail(response);
                return false;
            }
            if (!StringUtils.hasText(token) || !StringUtils.hasText(loginCode)) {
                onLoginFail(response);
                return false;
            }

            // 生成无状态Token
            StatelessToken statelessToken = new StatelessToken(loginCode, token);
            // 如果不执行登录会判断没有授权，直接退出

            subject.login(statelessToken);
        } catch (Exception e) {
            log.error(ExceptionCodeEnum.A0300.getCode(), e);
            onLoginFail(response);
            return false;
        }

        // 5、委托给Realm进行登录
        return true;

    }

    /**
     * 登录失败 写出信息
     */
    private void onLoginFail(ServletResponse response) throws IOException {
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        httpResponse.setCharacterEncoding(StandardCharsets.UTF_8.name());
        httpResponse.setStatus(HttpServletResponse.SC_OK);
        Response<?> resp = new Response<>();
        resp.setCode(ResultCodeEnum.UN_AUTHORIZED.getCode());
        resp.setMsg(ResultCodeEnum.UN_AUTHORIZED.getMessage());
        httpResponse.getWriter().write(JSON.toJSONString(resp));
    }
}
